mod command;
mod frame;
mod resp3;
mod value_deserializer;
mod value_into;

use std::fmt::Debug;

pub use command::*;
pub use frame::*;
pub use resp3::*;

use crate::{RedisError, RedisResult};
// pub use values::Value;

const TAG_SIMPLE_STRING: u8 = b'+';
const TAG_INTEGER: u8 = b':';
const TAG_BIG_NUMBER: u8 = b'(';
const TAG_BULK_STRING: u8 = b'$';
const TAG_ARRAY: u8 = b'*';
const TAG_MAP: u8 = b'%';
const TAG_SET: u8 = b'~';
const TAG_DOUBLE: u8 = b',';
const TAG_NIL: u8 = b'_';
const TAG_BOOL: u8 = b'#';
const TAG_VERBATIM_STRING: u8 = b'=';
const TAG_PUSHES: u8 = b'>';
const TAG_BULK_ERROR: u8 = b'!';
const TAG_SIMPLE_ERROR: u8 = b'-';

pub(crate) const SET_FAKE_FIELD: &str = "~~~SET~~~";
pub(crate) const ERROR_FAKE_FIELD: &str = "---ERROR---";
pub(crate) const PUSH_FAKE_FIELD: &str = ">>>PUSH>>>";

const CHAR_R: u8 = '\r' as u8;
const CHAR_N: u8 = '\n' as u8;

#[repr(u8)]
pub enum Value {
    Nil,
    SimpleString(Vec<u8>),
    Integer(i64),
    BigNumber(i128),
    Double(f64),
    BulkString(Vec<u8>),
    BulkError(Vec<u8>),
    Map(Vec<(Value, Value)>),
    Boolean(bool),
    Array(Vec<Value>),
    Set(Vec<Value>),
    Pushes(Vec<Value>),
    SimpleError(Vec<u8>),
    VerbatimString(String, Vec<u8>),
}

impl Value {
    pub(crate) fn read_error(&self) -> RedisResult<()> {
        let buf = match self {
            Value::SimpleError(s) => s,
            Value::BulkError(s) => s,
            _ => {
                return Ok(());
            }
        };
        match std::str::from_utf8(buf) {
            Ok(str) => Err(RedisError::Response(str.to_string())),
            Err(err) => Err(RedisError::new_response("error on read error", err)),
        }
    }

    // pub(crate) fn read_as_uize(self) -> RedisResult<usize> {
    //     match self {
    //         Value::Integer(val) => Ok(val as usize),
    //         _ => Err(RedisError::RespDeserialize(
    //             "the type of value to read couldn't into usize".to_string(),
    //         )),
    //     }
    // }

    // pub(crate) fn read_as_u32(self) -> RedisResult<u32> {
    //     match self {
    //         Value::Integer(val) => {
    //             if val < u32::MIN as i64 || val > u32::MAX as i64 {
    //                 Err(RedisError::RespDeserialize(
    //                     "the value to read is out of u32 range".to_string(),
    //                 ))
    //             } else {
    //                 Ok(val as u32)
    //             }
    //         }
    //         _ => Err(RedisError::RespDeserialize(
    //             "the type of value to read couldn't into u32".to_string(),
    //         )),
    //     }
    // }

    pub fn into_string(self) -> RedisResult<String> {
        match self {
            Value::SimpleString(buf)
            | Value::BulkString(buf)
            | Value::SimpleError(buf)
            | Value::BulkError(buf)
            | Value::VerbatimString(_, buf) => String::from_utf8(buf).map_err(|err| {
                RedisError::new_resp_deserialize("error on cast value into string", err)
            }),
            _ => Err(RedisError::RespDeserialize(
                "the value to read couldn't into string".to_string(),
            )),
        }
    }

    pub fn into_vec_u8(self) -> RedisResult<Vec<u8>> {
        match self {
            Value::SimpleString(buf)
            | Value::BulkString(buf)
            | Value::SimpleError(buf)
            | Value::BulkError(buf)
            | Value::VerbatimString(_, buf) => Ok(buf),
            _ => Err(RedisError::RespDeserialize(
                "the value couldn't into string".to_string(),
            )),
        }
    }
}

impl Debug for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::Nil => f.write_str("Nil"),
            Value::SimpleString(vec) => {
                f.write_str("SimpleString ")?;
                vec.fmt(f)
            }
            Value::Integer(val) => {
                f.write_str("Integer ")?;
                std::fmt::Debug::fmt(val, f)
            }
            Value::BigNumber(val) => {
                f.write_str("BigNumber ")?;
                std::fmt::Debug::fmt(val, f)
            }
            Value::Double(val) => {
                f.write_str("Double ")?;
                std::fmt::Debug::fmt(val, f)
            }
            Value::BulkString(vec) => {
                f.write_str("BulkString ")?;
                vec.fmt(f)
            }
            Value::BulkError(vec) => {
                f.write_str("BulkError ")?;
                vec.fmt(f)
            }
            Value::Map(map) => {
                f.write_str("Map ")?;
                map.fmt(f)
            }
            Value::Boolean(val) => {
                f.write_str("Boolean ")?;
                std::fmt::Debug::fmt(val, f)
            }
            Value::Array(val) => {
                f.write_str("Array ")?;
                val.fmt(f)
            }
            Value::Set(set) => {
                f.write_str("Set ")?;
                set.fmt(f)
            }
            Value::Pushes(pushes) => {
                f.write_str("Pushes ")?;
                pushes.fmt(f)
            }
            Value::SimpleError(vec) => {
                f.write_str("SimpleError ")?;
                vec.fmt(f)
            }
            Value::VerbatimString(encoding, vec) => {
                f.write_fmt(format_args!("{} {} ", "VerbatimString", encoding))?;
                vec.fmt(f)
            }
        }
    }
}

// impl PartialEq for Value {
//     fn eq(&self, other: &Self) -> bool {
//         match (self, other) {
//             (Self::SimpleString(l0), Self::SimpleString(r0)) => l0 == r0,
//             (Self::Integer(l0), Self::Integer(r0)) => l0 == r0,
//             (Self::BigNumber(l0), Self::BigNumber(r0)) => l0 == r0,
//             (Self::Double(l0), Self::Double(r0)) => l0 == r0,
//             (Self::BulkString(l0), Self::BulkString(r0)) => l0 == r0,
//             (Self::BulkError(l0), Self::BulkError(r0)) => l0 == r0,
//             (Self::Map(l0), Self::Map(r0)) => l0 == r0,
//             (Self::Boolean(l0), Self::Boolean(r0)) => l0 == r0,
//             (Self::Array(l0), Self::Array(r0)) => l0 == r0,
//             (Self::Set(l0), Self::Set(r0)) => l0 == r0,
//             (Self::Pushes(l0), Self::Pushes(r0)) => l0 == r0,
//             (Self::SimpleError(l0), Self::SimpleError(r0)) => l0 == r0,
//             (Self::VerbatimString(l0, l1), Self::VerbatimString(r0, r1)) => l0 == r0 && l1 == r1,
//             _ => core::mem::discriminant(self) == core::mem::discriminant(other),
//         }
//     }
// }

// impl Eq for Value {}

// impl Hash for Value {
//     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
//         match self {
//             Value::SimpleString(val) => val.hash(state),
//             Value::Integer(val) => val.hash(state),
//             Value::BigNumber(val) => val.hash(state),
//             Value::BulkString(val) => val.hash(state),
//             Value::BulkError(val) => val.hash(state),
//             Value::Boolean(val) => val.hash(state),
//             Value::Array(val) => val.hash(state),
//             Value::Set(val) => val.hash(state),
//             Value::Pushes(val) => val.hash(state),
//             Value::SimpleError(val) => val.hash(state),
//             Value::VerbatimString(_, val) => val.hash(state),
//             Value::Nil | Value::Double(_) | Value::Map(_) => state.write_u8(0),
//         }
//     }
// }
